package com.mytoutou.playermanager.player_manager.ui;


import com.mytoutou.playermanager.player_manager.Config;
import com.mytoutou.playermanager.player_manager.utils.Logger;
import ohos.agp.components.AttrSet;
import ohos.agp.graphics.SurfaceOps;
import ohos.agp.graphics.TextureHolder;
import ohos.app.Context;
import ohos.app.dispatcher.task.TaskPriority;
import ohos.biometrics.authentication.IFaceAuthentication;
import ohos.data.DatabaseHelper;
import ohos.data.preferences.Preferences;
import ohos.eventhandler.EventRunner;
import ohos.global.icu.text.NumberFormat;
import ohos.global.resource.RawFileDescriptor;
import ohos.media.player.Player;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * This is player implementation based on {@link ohos.agp.components.surfaceprovider.SurfaceProvider}
 * It encapsulates {@link Player}.
 * <p>
 * It ensures that MediaPlayer methods are called from not main thread.
 * MediaPlayer methods are directly connected with hardware. That's why they should not be called from UI thread
 *
 * @author danylo.volokh
 */
public class VideoPlayerView extends ScalableTextureView
        implements
        TextureView.SurfaceTextureListener,
        MediaPlayerWrapper.MainThreadMediaPlayerListener,
        MediaPlayerWrapper.VideoStateListener {

    private static final boolean SHOW_LOGS = Config.SHOW_LOGS;
    private String TAG = VideoPlayerView.class.getSimpleName();

    private static final String IS_VIDEO_MUTED = "IS_VIDEO_MUTED";

    // private HandlerThreadExtension mViewHandlerBackgroundThread;

    /**
     * A Listener that propagates {@link Player} listeners is background thread.
     * Probably call of this listener should also need to be synchronized with it creation and destroy places.
     */
    private BackgroundThreadMediaPlayerListener mMediaPlayerListenerBackgroundThread;

    private MediaPlayerWrapper.VideoStateListener mVideoStateListener;
    // private SurfaceTextureListener mLocalSurfaceTextureListener;

    private RawFileDescriptor mAssetFileDescriptor;
    private String mPath;

    private Context mContext;

    private final ReadyForPlaybackIndicator mReadyForPlaybackIndicator = new ReadyForPlaybackIndicator();

    private final Set<MediaPlayerWrapper.MainThreadMediaPlayerListener> mMediaPlayerMainThreadListeners = new HashSet<>();

    private SurfaceOps surfaceOps;
    private int videoHeight;
    private int videoWidth;


    /**
     * 手动重播
     */
    public void replay(boolean loopPlaying) {
        if (loopPlaying) {
            mMediaPlayer.rewindTo(0);
            mMediaPlayer.start();
        }
    }

    public int getVideoHeight() {
        return videoHeight;
    }

    public void setVideoHeight(int videoHeight) {
        this.videoHeight = videoHeight;
    }

    public int getVideoWidth() {
        return videoWidth;
    }

    public void setVideoWidth(int videoWidth) {
        this.videoWidth = videoWidth;
    }

    public MediaPlayerWrapper.State getCurrentState() {
        synchronized (mReadyForPlaybackIndicator) {
            return mMediaPlayer.getCurrentState();
        }
    }

    public RawFileDescriptor getAssetFileDescriptorDataSource() {
        return mAssetFileDescriptor;
    }

    public String getVideoUrlDataSource() {
        return mPath;
    }


    public interface BackgroundThreadMediaPlayerListener {
        void onVideoSizeChangedBackgroundThread(int width, int height);

        void onVideoPreparedBackgroundThread();

        void onVideoCompletionBackgroundThread();

        void onErrorBackgroundThread(int what, int extra);
    }

    public VideoPlayerView(Context context) {
        super(context);
        mContext = context;
        initView();
    }

    public VideoPlayerView(Context context, AttrSet attrs) {
        super(context, attrs);
        Logger.err(TAG + " context = " + context, "");
        mContext = context;
        initView();
    }

/*    public VideoPlayerView(Context context, Attr attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }*/

/*
    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public VideoPlayerView(Context context, AttrSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        initView();
    }
*/

    private void checkThread() {
        if (EventRunner.current() == EventRunner.getMainEventRunner()) {
            throw new RuntimeException("cannot be in main thread");
        }
    }

    public void reset() {
        checkThread();
        synchronized (mReadyForPlaybackIndicator) {
            mMediaPlayer.reset();
        }
    }

    public void release() {
        checkThread();
        synchronized (mReadyForPlaybackIndicator) {
            mMediaPlayer.release();
        }
    }

    public void clearPlayerInstance() {
        if (SHOW_LOGS) Logger.v(TAG, ">> clearPlayerInstance");

        checkThread();

        synchronized (mReadyForPlaybackIndicator) {
            mReadyForPlaybackIndicator.setVideoSize(null, null);
            mMediaPlayer.clearAll();
            mMediaPlayer = null;
        }

        if (SHOW_LOGS) Logger.v(TAG, "<< clearPlayerInstance");
    }

    public void createNewPlayerInstance() {
        if (SHOW_LOGS) Logger.v(TAG, ">> createNewPlayerInstance");

        if (SHOW_LOGS) Logger.v(TAG, "createNewPlayerInstance main Looper " + EventRunner.getMainEventRunner());
        if (SHOW_LOGS) Logger.v(TAG, "createNewPlayerInstance my Looper " + EventRunner.current());
        checkThread();
        synchronized (mReadyForPlaybackIndicator) {

            //创建Player
            mMediaPlayer = new MediaPlayerWrapperImpl(getContext(), getVideoHeight(), getVideoWidth());
//            mMediaPlayer.setVideoH(2200);
            // 设置时评宽和高
            mReadyForPlaybackIndicator.setVideoSize(null, null);
            mReadyForPlaybackIndicator.setFailedToPrepareUiForPlayback(false);
            Logger.v(TAG, "isSurfaceTextureAvailable =" + mReadyForPlaybackIndicator.isSurfaceTextureAvailable());
            mMediaPlayer.setMainThreadMediaPlayerListener(this);
            mMediaPlayer.setVideoStateListener(this);
        }
        if (SHOW_LOGS) Logger.v(TAG, "<< createNewPlayerInstance");
    }

    public void prepare() {
        checkThread();
        synchronized (mReadyForPlaybackIndicator) {
            mMediaPlayer.prepare();
        }
    }

    public void stop() {
        checkThread();
        synchronized (mReadyForPlaybackIndicator) {
            mMediaPlayer.stop();
        }
    }

    private void notifyOnVideoStopped() {
        if (SHOW_LOGS) Logger.v(TAG, "notifyOnVideoStopped");
        List<MediaPlayerWrapper.MainThreadMediaPlayerListener> listCopy;
        synchronized (mMediaPlayerMainThreadListeners) {
            listCopy = new ArrayList<>(mMediaPlayerMainThreadListeners);
        }
        for (MediaPlayerWrapper.MainThreadMediaPlayerListener listener : listCopy) {
            listener.onVideoStoppedMainThread();
        }
    }

    private boolean isVideoSizeAvailable() {
        boolean isVideoSizeAvailable = getContentHeight() != null && getContentWidth() != null;
        if (SHOW_LOGS) Logger.v(TAG, "isVideoSizeAvailable " + isVideoSizeAvailable);
        return isVideoSizeAvailable;
    }

    public void start() {
        if (SHOW_LOGS) Logger.v(TAG, ">> start");
        synchronized (mReadyForPlaybackIndicator) {
            if (mReadyForPlaybackIndicator.isReadyForPlayback()) {
                mMediaPlayer.start();
            } else {
                if (SHOW_LOGS) Logger.v(TAG, "start, >> wait");
                if (!mReadyForPlaybackIndicator.isFailedToPrepareUiForPlayback()) {
                    try {
                        mReadyForPlaybackIndicator.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }

                    if (SHOW_LOGS) Logger.v(TAG, "start, << wait");

                    if (mReadyForPlaybackIndicator.isReadyForPlayback()) {
                        mMediaPlayer.start();
                    } else {
                        if (SHOW_LOGS)
                            Logger.w(TAG, "start, movie is not ready, Player become STARTED state, but it will actually don't play");
                    }
                } else {
                    if (SHOW_LOGS) Logger.w(TAG, "start, movie is not ready. Video size will not become available");
                }
            }
        }
        if (SHOW_LOGS) Logger.v(TAG, "<< start");
    }

    private void initView() {
        TAG = "" + this;
        if (SHOW_LOGS) Logger.v(TAG, "initView");
        setScaleType(ScaleType.CENTER_CROP);
        super.setSurfaceTextureListener(this);

  /*      mViewHandlerBackgroundThread = new HandlerThreadExtension(TAG, false);
        mViewHandlerBackgroundThread.startThread();*/
    }

    @Override
    public final void setSurfaceTextureListener(SurfaceTextureListener listener) {
        mLocalSurfaceTextureListener = listener;
    }

    public void setDataSource(String path) {
        checkThread();
        synchronized (mReadyForPlaybackIndicator) {

            if (SHOW_LOGS) Logger.v(TAG, "setDataSource, path " + path + ", this " + this);

            try {
                mMediaPlayer.setDataSource(path);
                mMediaPlayer.setLooping(true);
            } catch (IOException e) {
                Logger.d(TAG, e.getMessage());
                throw new RuntimeException(e);
            }
            mPath = path;
            setVideoSurface();
        }
    }

    public void setDataSource(RawFileDescriptor assetFileDescriptor) {
        checkThread();
        synchronized (mReadyForPlaybackIndicator) {
            if (SHOW_LOGS)
                Logger.v(TAG, "setDataSource, assetFileDescriptor " + assetFileDescriptor + ", this " + this);

            try {
                mMediaPlayer.setDataSource(assetFileDescriptor);
            } catch (IOException e) {
                Logger.d(TAG, e.getMessage());
                throw new RuntimeException(e);
            }
            mAssetFileDescriptor = assetFileDescriptor;
            setVideoSurface();
        }
    }

    private void setVideoSurface() {

        /*  if (mReadyForPlaybackIndicator.isSurfaceTextureAvailable()) {
         *//* TextureHolder texture = getSurfaceTexture();
                if (SHOW_LOGS) Logger.v(TAG, "texture " + texture);
                mMediaPlayer.setSurfaceTexture(texture);*//*
            Logger.v(TAG, "surfaceOps = " + surfaceOps.getSurface());
            mMediaPlayer.setSurface(surfaceOps.getSurface());
        } else {
            if (SHOW_LOGS) Logger.v(TAG, "texture not available");
        }*/

        while (!mReadyForPlaybackIndicator.isSurfaceTextureAvailable()) ;
        mMediaPlayer.setSurface(surfaceOps.getSurface());


        mMediaPlayer.initParams();
        getContext().getMainTaskDispatcher().syncDispatch(
                () -> {
                    mMediaPlayer.initPlayerViewSize(this);
                }
        );
    }

    public void setOnVideoStateChangedListener(MediaPlayerWrapper.VideoStateListener listener) {
        mVideoStateListener = listener;
        checkThread();
        synchronized (mReadyForPlaybackIndicator) {
            mMediaPlayer.setVideoStateListener(listener);
        }
    }

    public void addMediaPlayerListener(MediaPlayerWrapper.MainThreadMediaPlayerListener listener) {
        synchronized (mMediaPlayerMainThreadListeners) {
            mMediaPlayerMainThreadListeners.add(listener);
        }
    }

    public void setBackgroundThreadMediaPlayerListener(BackgroundThreadMediaPlayerListener listener) {
        mMediaPlayerListenerBackgroundThread = listener;
    }

    @Override
    public void onVideoSizeChangedMainThread(int width, int height) {

        if (SHOW_LOGS) Logger.v(TAG, ">> onVideoSizeChangedMainThread, width " + width + ", height " + height);

        if (width != 0 && height != 0) {
            setContentWidth(width);
            setContentHeight(height);
            onVideoSizeAvailable();
        } else {
            if (SHOW_LOGS)
                Logger.w(TAG, "onVideoSizeChangedMainThread, size 0. Probably will be unable to start video");
            synchronized (mReadyForPlaybackIndicator) {
                mReadyForPlaybackIndicator.setFailedToPrepareUiForPlayback(true);
                mReadyForPlaybackIndicator.notifyAll();
            }
        }

        notifyOnVideoSizeChangedMainThread(width, height);

        if (SHOW_LOGS) Logger.v(TAG, "<< onVideoSizeChangedMainThread, width " + width + ", height " + height);
    }

    private void notifyOnVideoSizeChangedMainThread(int width, int height) {
        if (SHOW_LOGS) Logger.v(TAG, "notifyOnVideoSizeChangedMainThread, width " + width + ", height " + height);
        List<MediaPlayerWrapper.MainThreadMediaPlayerListener> listCopy;
        synchronized (mMediaPlayerMainThreadListeners) {
            listCopy = new ArrayList<>(mMediaPlayerMainThreadListeners);
        }
        for (MediaPlayerWrapper.MainThreadMediaPlayerListener listener : listCopy) {
            listener.onVideoSizeChangedMainThread(width, height);
        }
    }

    private final Runnable mVideoCompletionBackgroundThreadRunnable = new Runnable() {
        @Override
        public void run() {
            mMediaPlayerListenerBackgroundThread.onVideoSizeChangedBackgroundThread(getContentHeight(), getContentWidth());
        }
    };

    @Override
    public void onVideoCompletionMainThread() {
        notifyOnVideoCompletionMainThread();
       /* if (mMediaPlayerListenerBackgroundThread != null) {
            mViewHandlerBackgroundThread.post(mVideoCompletionBackgroundThreadRunnable);
        }*/
    }

    private void notifyOnVideoCompletionMainThread() {
        if (SHOW_LOGS) Logger.v(TAG, "notifyVideoCompletionMainThread");
        List<MediaPlayerWrapper.MainThreadMediaPlayerListener> listCopy;
        synchronized (mMediaPlayerMainThreadListeners) {
            listCopy = new ArrayList<>(mMediaPlayerMainThreadListeners);
        }
        for (MediaPlayerWrapper.MainThreadMediaPlayerListener listener : listCopy) {
            listener.onVideoCompletionMainThread();
        }
    }

    private void notifyOnVideoPreparedMainThread() {
        if (SHOW_LOGS) Logger.v(TAG, "notifyOnVideoPreparedMainThread");
        List<MediaPlayerWrapper.MainThreadMediaPlayerListener> listCopy;
        synchronized (mMediaPlayerMainThreadListeners) {
            listCopy = new ArrayList<>(mMediaPlayerMainThreadListeners);
        }
        for (MediaPlayerWrapper.MainThreadMediaPlayerListener listener : listCopy) {
            listener.onVideoPreparedMainThread();
        }
    }

    private void notifyOnErrorMainThread(int what, int extra) {
        if (SHOW_LOGS) Logger.v(TAG, "notifyOnErrorMainThread");
        List<MediaPlayerWrapper.MainThreadMediaPlayerListener> listCopy;
        synchronized (mMediaPlayerMainThreadListeners) {
            listCopy = new ArrayList<>(mMediaPlayerMainThreadListeners);
        }
        for (MediaPlayerWrapper.MainThreadMediaPlayerListener listener : listCopy) {
            listener.onErrorMainThread(what, extra);
        }
    }

    private final Runnable mVideoPreparedBackgroundThreadRunnable = new Runnable() {
        @Override
        public void run() {
            // mMediaPlayerListenerBackgroundThread.onVideoPreparedBackgroundThread();
        }
    };

    @Override
    public void onVideoPreparedMainThread() {

        Logger.v(TAG, "   mMediaPlayerListenerBackgroundThread = " + mMediaPlayerListenerBackgroundThread);
        notifyOnVideoPreparedMainThread();

      /*  if (mMediaPlayerListenerBackgroundThread != null) {

            mViewHandlerBackgroundThread.post(mVideoPreparedBackgroundThreadRunnable);
        }*/
    }

    public static final int MEDIA_ERROR_UNKNOWN = 1;

    /**
     * Media server died. In this case, the application must release the
     * MediaPlayer object and instantiate a new one.
     */
    public static final int MEDIA_ERROR_SERVER_DIED = 100;

    /**
     * The video is streamed and its container is not valid for progressive
     * playback i.e the video's index (e.g moov atom) is not at the start of the
     * file.
     */
    public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = 200;

    /**
     * File or network related operation errors.
     */
    public static final int MEDIA_ERROR_IO = -1004;
    /**
     * Bitstream is not conforming to the related coding standard or file spec.
     */
    public static final int MEDIA_ERROR_MALFORMED = -1007;
    /**
     * Bitstream is conforming to the related coding standard or file spec, but
     * the media framework does not support the feature.
     */
    public static final int MEDIA_ERROR_UNSUPPORTED = -1010;
    /**
     * Some operation takes too long to complete, usually more than 3-5 seconds.
     */
    public static final int MEDIA_ERROR_TIMED_OUT = -110;


    @Override
    public void onErrorMainThread(final int what, final int extra) {
        if (SHOW_LOGS) Logger.v(TAG, "onErrorMainThread, this " + VideoPlayerView.this);
        switch (what) {
            case MEDIA_ERROR_SERVER_DIED:
                if (SHOW_LOGS) Logger.v(TAG, "onErrorMainThread, what MEDIA_ERROR_SERVER_DIED");
                printErrorExtra(extra);
                break;
            case MEDIA_ERROR_UNKNOWN:
                if (SHOW_LOGS) Logger.v(TAG, "onErrorMainThread, what MEDIA_ERROR_UNKNOWN");
                printErrorExtra(extra);
                break;
        }

        notifyOnErrorMainThread(what, extra);

    }

    @Override
    public void onBufferingUpdateMainThread(int percent) {

    }

    @Override
    public void onVideoStoppedMainThread() {
        notifyOnVideoStopped();
    }

    private void printErrorExtra(int extra) {
        switch (extra) {
            case MEDIA_ERROR_IO:
                if (SHOW_LOGS) Logger.v(TAG, "error extra MEDIA_ERROR_IO");
                break;
            case MEDIA_ERROR_MALFORMED:
                if (SHOW_LOGS) Logger.v(TAG, "error extra MEDIA_ERROR_MALFORMED");
                break;
            case MEDIA_ERROR_UNSUPPORTED:
                if (SHOW_LOGS) Logger.v(TAG, "error extra MEDIA_ERROR_UNSUPPORTED");
                break;
            case MEDIA_ERROR_TIMED_OUT:
                if (SHOW_LOGS) Logger.v(TAG, "error extra MEDIA_ERROR_TIMED_OUT");
                break;
        }
    }

    private final Runnable mVideoSizeAvailableRunnable = new Runnable() {
        @Override
        public void run() {
            if (SHOW_LOGS) Logger.v(TAG, ">> run, onVideoSizeAvailable");

            synchronized (mReadyForPlaybackIndicator) {
                if (SHOW_LOGS)
                    Logger.v(TAG, "onVideoSizeAvailable, mReadyForPlaybackIndicator " + mReadyForPlaybackIndicator);

                mReadyForPlaybackIndicator.setVideoSize(getContentHeight(), getContentWidth());

                if (mReadyForPlaybackIndicator.isReadyForPlayback()) {
                    if (SHOW_LOGS) Logger.v(TAG, "run, onVideoSizeAvailable, notifyAll");

                    mReadyForPlaybackIndicator.notifyAll();
                }
                if (SHOW_LOGS) Logger.v(TAG, "<< run, onVideoSizeAvailable");
            }
            if (mMediaPlayerListenerBackgroundThread != null) {
                mMediaPlayerListenerBackgroundThread.onVideoSizeChangedBackgroundThread(getContentHeight(), getContentWidth());
            }
        }
    };

    private void onVideoSizeAvailable() {
        if (SHOW_LOGS) Logger.v(TAG, ">> onVideoSizeAvailable");

        updateTextureViewSize();

        if (isBoundToWindow()) {
            //  mViewHandlerBackgroundThread.post(mVideoSizeAvailableRunnable);
        }

        if (SHOW_LOGS) Logger.v(TAG, "<< onVideoSizeAvailable");
    }

    private Preferences preferences = new DatabaseHelper(getContext()).getPreferences("VideoPlayerView");

    public void muteVideo() {
        synchronized (mReadyForPlaybackIndicator) {

            preferences.putBoolean(IS_VIDEO_MUTED, true).flush();
            //(getContext()).edit().putBoolean(IS_VIDEO_MUTED, true).commit();
            mMediaPlayer.setVolume(0, 0);
        }
    }

    public void unMuteVideo() {
        synchronized (mReadyForPlaybackIndicator) {
            preferences.putBoolean(IS_VIDEO_MUTED, false).flush();
            mMediaPlayer.setVolume(1, 1);
        }
    }

    public boolean isAllVideoMute() {
        return preferences.getBoolean(IS_VIDEO_MUTED, false);
    }

    public void pause() {
        if (SHOW_LOGS) Logger.d(TAG, ">> pause ");
        synchronized (mReadyForPlaybackIndicator) {
            mMediaPlayer.pause();
        }
        if (SHOW_LOGS) Logger.d(TAG, "<< pause");
    }

    /**
     * @see Player#getDuration()
     */
    public int getDuration() {
        synchronized (mReadyForPlaybackIndicator) {
            return mMediaPlayer.getDuration();
        }
    }

    @Override
    public void onSurfaceTextureAvailable(SurfaceOps surfaceTexture, int width, int height) {
        if (SHOW_LOGS)
            Logger.v(TAG, "onSurfaceTextureAvailable, width " + width + ", height " + height + ", this " + this);
       /* if(mLocalSurfaceTextureListener != null){
            mLocalSurfaceTextureListener.onSurfaceTextureAvailable(surfaceTexture, width, height);
        }*/
        surfaceOps = surfaceTexture;
        Logger.v(TAG, "surfaceOps = " + surfaceOps);
        notifyTextureAvailable();
    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceOps surface, int width, int height) {
      /*  if(mLocalSurfaceTextureListener != null){
            mLocalSurfaceTextureListener.onSurfaceTextureSizeChanged(surface, width, height);
        }*/
    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceOps surface) {
        if (SHOW_LOGS) Logger.v(TAG, "onSurfaceTextureDestroyed, surface " + surface);

    /*    if(mLocalSurfaceTextureListener != null){
            mLocalSurfaceTextureListener.onSurfaceTextureDestroyed(surface);
        }*/

        if (isBoundToWindow()) {
      /*      mViewHandlerBackgroundThread.post(new Runnable() {
                @Override
                public void run() {

                    synchronized (mReadyForPlaybackIndicator) {
                        mReadyForPlaybackIndicator.setSurfaceTextureAvailable(false);

                        *//** we have to notify a Thread may be in wait() state in {@link VideoPlayerView#start()} method*//*
                        mReadyForPlaybackIndicator.notifyAll();
                    }
                }
            });*/
        }

        // We have to release this surface manually for better control.
        // Also we do this because we return false from this method

        return false;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceOps surface) {
        if (mLocalSurfaceTextureListener != null) {
            mLocalSurfaceTextureListener.onSurfaceTextureUpdated(surface);
        }
    }


    private void notifyTextureAvailable() {
        if (SHOW_LOGS) Logger.v(TAG, ">> notifyTextureAvailable");

        mContext.getGlobalTaskDispatcher(TaskPriority.DEFAULT).syncDispatch(
                new Runnable() {
                    @Override
                    public void run() {
                        if (SHOW_LOGS) Logger.v(TAG, ">> run notifyTextureAvailable");

                        //  synchronized (mReadyForPlaybackIndicator) {

                        if (mMediaPlayer != null) {
                            mMediaPlayer.setSurfaceTexture(new TextureHolder(222));
                        } else {
                            mReadyForPlaybackIndicator.setVideoSize(null, null);
                            if (SHOW_LOGS)
                                Logger.v(TAG, "mMediaPlayer null, cannot set surface texture");
                        }
                        mReadyForPlaybackIndicator.setSurfaceTextureAvailable(true);

                        if (mReadyForPlaybackIndicator.isReadyForPlayback()) {

                            if (SHOW_LOGS) Logger.v(TAG, "notify ready for playback");
                            //mReadyForPlaybackIndicator.notifyAll();
                        }
                        // }

                        if (SHOW_LOGS) Logger.v(TAG, "<< run notifyTextureAvailable");
                    }
                }
        );

  /*      mViewHandlerBackgroundThread.post(new Runnable() {
            @Override
            public void run() {
                if (SHOW_LOGS) Logger.v(TAG, ">> run notifyTextureAvailable");

                synchronized (mReadyForPlaybackIndicator) {

                    if (mMediaPlayer != null) {
                        mMediaPlayer.setSurfaceTexture(new TextureHolder(222));
                    } else {
                        mReadyForPlaybackIndicator.setVideoSize(null, null);
                        if (SHOW_LOGS)
                            Logger.v(TAG, "mMediaPlayer null, cannot set surface texture");
                    }
                    mReadyForPlaybackIndicator.setSurfaceTextureAvailable(true);

                    if (mReadyForPlaybackIndicator.isReadyForPlayback()) {

                        if (SHOW_LOGS) Logger.v(TAG, "notify ready for playback");
                        mReadyForPlaybackIndicator.notifyAll();
                    }
                }

                if (SHOW_LOGS) Logger.v(TAG, "<< run notifyTextureAvailable");
            }
        });*/
        if (SHOW_LOGS) Logger.v(TAG, "<< notifyTextureAvailable");
    }

    public interface PlaybackStartedListener {
        void onPlaybackStarted();
    }

    @Override
    public boolean isBoundToWindow() {
        Logger.v(TAG, "isBoundToWindow");
        // return mViewHandlerBackgroundThread != null;
        return true;
    }



   /* @Override
    public void onSurfaceTextureUpdated(SurfaceOps surface) {
        //    if (SHOW_LOGS) Logger.v(TAG, "onSurfaceTextureUpdated, mIsVideoStartedCalled " + mIsVideoStartedCalled.get() + ", mMediaPlayer.getState() " + mMediaPlayer.getState());
        if(mLocalSurfaceTextureListener != null){
            mLocalSurfaceTextureListener.onSurfaceTextureUpdated(surface);
        }
    }*/


    @Override
    public void onVideoPlayTimeChanged(int positionInMilliseconds) {
        int duration = mMediaPlayer.getDuration();
        NumberFormat numberFormat = NumberFormat.getInstance();
        // 设置精确到小数点后2位
//        numberFormat.setMaximumFractionDigits(2);
        String result = numberFormat.format((float) positionInMilliseconds / (float) duration * 100);
        int percent = Double.valueOf(result).intValue();
//        mMediaPlayer.seekToPercent(percent);
//        mMediaPlayer.rewindTo(positionInMilliseconds);
    }

    //改变播放进度
    public void rewindTo(long microseconds) {
        mMediaPlayer.rewindTo(microseconds);
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() + "@" + hashCode();
    }

/*    @Override
    protected void onVisibilityChanged(View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        boolean isInEditMode = false();

        if (SHOW_LOGS) Logger.v(TAG, ">> onVisibilityChanged " + visibilityStr(visibility) + ", isInEditMode " + isInEditMode);
        if (!isInEditMode) {

            switch (visibility){
                case VISIBLE:
                    break;
                case INVISIBLE:
                case HIDE:
                    synchronized (mReadyForPlaybackIndicator){
                        // have to notify worker thread in case we exited this screen without getting ready for playback
                        mReadyForPlaybackIndicator.notifyAll();
                    }
            }
        }

        if (SHOW_LOGS) Logger.v(TAG, "<< onVisibilityChanged");
    }*/

    private static String visibilityStr(int visibility) {
        switch (visibility) {
            case VISIBLE:
                return "VISIBLE";
            case INVISIBLE:
                return "INVISIBLE";
            case HIDE:
                return "GONE";
            default:
                throw new RuntimeException("unexpected");
        }
    }


}
